/***************************************************************
Copyright © 206cd Co., Ltd. 1998-2029. All rights reserved.
文件名		: drm_plane_drv.c
作者	  	: gaoweijun
版本	   	: V1.0
描述	   	: drm plane驱动文件。
其他	   	: 无
日志	   	: 初版V1.0 2021/10/12 创建
***************************************************************/

#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <time.h>
#include <unistd.h>
#include <inttypes.h>
#include <assert.h>
#include "drm_plane_drv.h"
#include "debug.h"

#define PRINT_LEVEL DEBUG

//int fd_all=0;
//uint32_t crtc_id_all=40;

struct crtc {
    drmModeCrtc *crtc;
    drmModeObjectProperties *props;
    drmModePropertyRes **props_info;
    drmModeModeInfo *mode;
};

struct encoder {
    drmModeEncoder *encoder;
};

struct connector {
    drmModeConnector *connector;
    drmModeObjectProperties *props;
    drmModePropertyRes **props_info;
    char *name;
};

struct fb {
    drmModeFB *fb;
};

struct plane {
    drmModePlane *plane;
    drmModeObjectProperties *props;
    drmModePropertyRes **props_info;
};

struct resources {
    drmModeRes *res;
    drmModePlaneRes *plane_res;

    struct crtc *crtcs;
    struct encoder *encoders;
    struct connector *connectors;
    struct fb *fbs;
    struct plane *planes;
};

struct device {
    int fd;
    struct resources *resources;
};

struct drm_buffers{
    int32_t width, height;
    int buf_num;
    unsigned int fourcc;
   struct drm_buffer_object *bo;
};


static inline int64_t U642I64(uint64_t val)
{
    return (int64_t)*((int64_t *)&val);
}

#ifndef ARRAY_SIZE
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
#endif

#define bit_name_fn(res)					\
const char * res##_str(int type) {				\
    unsigned int i;						\
    const char *sep = "";					\
    for (i = 0; i < ARRAY_SIZE(res##_names); i++) {		\
        if (type & (1 << i)) {				\
            printf("%s%s", sep, res##_names[i]);	\
            sep = ", ";				\
        }						\
    }							\
    return NULL;						\
}

static const char *mode_type_names[] = {
    "builtin",
    "clock_c",
    "crtc_c",
    "preferred",
    "default",
    "userdef",
    "driver",
};

static bit_name_fn(mode_type)

static const char *mode_flag_names[] = {
    "phsync",
    "nhsync",
    "pvsync",
    "nvsync",
    "interlace",
    "dblscan",
    "csync",
    "pcsync",
    "ncsync",
    "hskew",
    "bcast",
    "pixmux",
    "dblclk",
    "clkdiv2"
};

static bit_name_fn(mode_flag)

static void dump_fourcc(uint32_t fourcc)
{
    printf(" %c%c%c%c",
        fourcc,
        fourcc >> 8,
        fourcc >> 16,
        fourcc >> 24);
}

static void dump_encoders(struct device *dev)
{
    drmModeEncoder *encoder;
    int i;

    printf("Encoders:\n");
    printf("id\tcrtc\ttype\tpossible crtcs\tpossible clones\t\n");
    for (i = 0; i < dev->resources->res->count_encoders; i++) {
        encoder = dev->resources->encoders[i].encoder;
        if (!encoder)
            continue;

        printf("%d\t%d\t%s\t0x%08x\t0x%08x\n",
               encoder->encoder_id,
               encoder->crtc_id,
               "gwj-unkown",
               encoder->possible_crtcs,
               encoder->possible_clones);
    }
    printf("\n");
}

static void dump_mode(drmModeModeInfo *mode,int j)
{
    printf(" %d %s %d %d %d %d %d %d %d %d %d %d",
           j,
           mode->name,
           mode->vrefresh,
           mode->hdisplay,
           mode->hsync_start,
           mode->hsync_end,
           mode->htotal,
           mode->vdisplay,
           mode->vsync_start,
           mode->vsync_end,
           mode->vtotal,
           mode->clock);

    printf(" flags: ");
    mode_flag_str(mode->flags);
    printf("; type: ");
    mode_type_str(mode->type);
    printf("\r\n");
}

static void dump_blob(struct device *dev , uint32_t blob_id)
{
    uint32_t i;
    unsigned char *blob_data;
    drmModePropertyBlobPtr blob;

    blob = drmModeGetPropertyBlob(dev->fd, blob_id);
    if (!blob) {
        printf("\n");
        return;
    }

    blob_data = blob->data;

    for (i = 0; i < blob->length; i++) {
        if (i % 16 == 0)
            printf("\n\t\t\t");
        printf("%.2hhx", blob_data[i]);
    }
    printf("\n");

    drmModeFreePropertyBlob(blob);
}
static const char *modifier_to_string(uint64_t modifier)
{
    switch (modifier) {
    case DRM_FORMAT_MOD_INVALID:
        return "INVALID";
    case DRM_FORMAT_MOD_LINEAR:
        return "LINEAR";
    case I915_FORMAT_MOD_X_TILED:
        return "X_TILED";
    case I915_FORMAT_MOD_Y_TILED:
        return "Y_TILED";
    case I915_FORMAT_MOD_Yf_TILED:
        return "Yf_TILED";
    case I915_FORMAT_MOD_Y_TILED_CCS:
        return "Y_TILED_CCS";
    case I915_FORMAT_MOD_Yf_TILED_CCS:
        return "Yf_TILED_CCS";
    case DRM_FORMAT_MOD_SAMSUNG_64_32_TILE:
        return "SAMSUNG_64_32_TILE";
    case DRM_FORMAT_MOD_VIVANTE_TILED:
        return "VIVANTE_TILED";
    case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
        return "VIVANTE_SUPER_TILED";
    case DRM_FORMAT_MOD_VIVANTE_SPLIT_TILED:
        return "VIVANTE_SPLIT_TILED";
    case DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED:
        return "VIVANTE_SPLIT_SUPER_TILED";
    case DRM_FORMAT_MOD_NVIDIA_TEGRA_TILED:
        return "NVIDIA_TEGRA_TILED";
    case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(0):
        return "NVIDIA_16BX2_BLOCK(0)";
    case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(1):
        return "NVIDIA_16BX2_BLOCK(1)";
    case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(2):
        return "NVIDIA_16BX2_BLOCK(2)";
    case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(3):
        return "NVIDIA_16BX2_BLOCK(3)";
    case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(4):
        return "NVIDIA_16BX2_BLOCK(4)";
    case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(5):
        return "NVIDIA_16BX2_BLOCK(5)";
    case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
        return "MOD_BROADCOM_VC4_T_TILED";
    case DRM_FORMAT_MOD_QCOM_COMPRESSED:
        return "QCOM_COMPRESSED";
    default:
        return "(UNKNOWN MODIFIER)";
    }
}
static void dump_in_formats(struct device *dev, uint32_t blob_id)
{
    uint32_t i, j;
    drmModePropertyBlobPtr blob;
    struct drm_format_modifier_blob *header;
    uint32_t *formats;
    struct drm_format_modifier *modifiers;

    printf("\t\tin_formats blob decoded:\n");
    blob = drmModeGetPropertyBlob(dev->fd, blob_id);
    if (!blob) {
        printf("\n");
        return;
    }

    header = blob->data;
    formats = (uint32_t *) ((char *) header + header->formats_offset);
    modifiers = (struct drm_format_modifier *)
        ((char *) header + header->modifiers_offset);

    for (i = 0; i < header->count_formats; i++) {
        printf("\t\t\t");
        dump_fourcc(formats[i]);
        printf(": ");
        for (j = 0; j < header->count_modifiers; j++) {
            uint64_t mask = 1ULL << i;
            if (modifiers[j].formats & mask)
                printf(" %s", modifier_to_string(modifiers[j].modifier));
        }
        printf("\n");
    }

    drmModeFreePropertyBlob(blob);
}

static void dump_prop(struct device *dev, drmModePropertyPtr prop,
              uint32_t prop_id, uint64_t value)
{
    int i;
    printf("\t%d", prop_id);
    if (!prop) {
        printf("\n");
        return;
    }

    printf(" %s:\n", prop->name);

    printf("\t\tflags:");
    if (prop->flags & DRM_MODE_PROP_PENDING)
        printf(" pending");
    if (prop->flags & DRM_MODE_PROP_IMMUTABLE)
        printf(" immutable");
    if (drm_property_type_is(prop, DRM_MODE_PROP_SIGNED_RANGE))
        printf(" signed range");
    if (drm_property_type_is(prop, DRM_MODE_PROP_RANGE))
        printf(" range");
    if (drm_property_type_is(prop, DRM_MODE_PROP_ENUM))
        printf(" enum");
    if (drm_property_type_is(prop, DRM_MODE_PROP_BITMASK))
        printf(" bitmask");
    if (drm_property_type_is(prop, DRM_MODE_PROP_BLOB))
        printf(" blob");
    if (drm_property_type_is(prop, DRM_MODE_PROP_OBJECT))
        printf(" object");
    printf("\n");

    if (drm_property_type_is(prop, DRM_MODE_PROP_SIGNED_RANGE)) {
        printf("\t\tvalues:");
        for (i = 0; i < prop->count_values; i++)
            printf(" %"PRId64, U642I64(prop->values[i]));
        printf("\n");
    }

    if (drm_property_type_is(prop, DRM_MODE_PROP_RANGE)) {
        printf("\t\tvalues:");
        for (i = 0; i < prop->count_values; i++)
            printf(" %"PRIu64, prop->values[i]);
        printf("\n");
    }

    if (drm_property_type_is(prop, DRM_MODE_PROP_ENUM)) {
        printf("\t\tenums:");
        for (i = 0; i < prop->count_enums; i++)
            printf(" %s=%llu", prop->enums[i].name,
                   prop->enums[i].value);
        printf("\n");
    } else if (drm_property_type_is(prop, DRM_MODE_PROP_BITMASK)) {
        printf("\t\tvalues:");
        for (i = 0; i < prop->count_enums; i++)
            printf(" %s=0x%llx", prop->enums[i].name,
                   (1LL << prop->enums[i].value));
        printf("\n");
    } else {
        assert(prop->count_enums == 0);
    }

    if (drm_property_type_is(prop, DRM_MODE_PROP_BLOB)) {
        printf("\t\tblobs:\n");
        for (i = 0; i < prop->count_blobs; i++)
            dump_blob(dev, prop->blob_ids[i]);
        printf("\n");
    } else {
        assert(prop->count_blobs == 0);
    }

    printf("\t\tvalue:");
    if (drm_property_type_is(prop, DRM_MODE_PROP_BLOB))
        dump_blob(dev, value);
    else if (drm_property_type_is(prop, DRM_MODE_PROP_SIGNED_RANGE))
        printf(" %"PRId64"\n", value);
    else
        printf(" %"PRIu64"\n", value);

    if (strcmp(prop->name, "IN_FORMATS") == 0)
        dump_in_formats(dev, value);
}

static void dump_connectors(struct device *dev)
{
    int i, j;

    printf("Connectors:\n");
    printf("id\tencoder\tstatus\t\tname\t\tsize (mm)\tmodes\tencoders\n");
    for (i = 0; i < dev->resources->res->count_connectors; i++) {
        struct connector *_connector = &dev->resources->connectors[i];
        drmModeConnector *connector = _connector->connector;
        if (!connector)
            continue;

        printf("%d\t%d\t%s\t%-15s\t%dx%d\t\t%d\t",
               connector->connector_id,
               connector->encoder_id,
               "gwj-unkown",
               _connector->name,
               connector->mmWidth, connector->mmHeight,
               connector->count_modes);

        for (j = 0; j < connector->count_encoders; j++)
            printf("%s%d", j > 0 ? ", " : "", connector->encoders[j]);
        printf("\n");

        if (connector->count_modes) {
            printf("  modes:\n");
            printf("\tindex name refresh (Hz) hdisp hss hse htot vdisp "
                   "vss vse vtot)\n");
            for (j = 0; j < connector->count_modes; j++)
                dump_mode(&connector->modes[j],j);
        }

        if (_connector->props) {
            printf("  props:\n");
            for (j = 0; j < (int)_connector->props->count_props; j++)
                dump_prop(dev, _connector->props_info[j],
                      _connector->props->props[j],
                      _connector->props->prop_values[j]);
        }
    }
    printf("\n");
}

static void dump_crtcs(struct device *dev)
{
    int i;
    uint32_t j;

    printf("CRTCs:\n");
    printf("id\tfb\tpos\tsize\n");
    for (i = 0; i < dev->resources->res->count_crtcs; i++) {
        struct crtc *_crtc = &dev->resources->crtcs[i];
        drmModeCrtc *crtc = _crtc->crtc;
        if (!crtc)
            continue;

        printf("%d\t%d\t(%d,%d)\t(%dx%d)\n",
               crtc->crtc_id,
               crtc->buffer_id,
               crtc->x, crtc->y,
               crtc->width, crtc->height);
        dump_mode(&crtc->mode,0);

        if (_crtc->props) {
            printf("  props:\n");
            for (j = 0; j < _crtc->props->count_props; j++)
                dump_prop(dev, _crtc->props_info[j],
                      _crtc->props->props[j],
                      _crtc->props->prop_values[j]);
        } else {
            printf("  no properties found\n");
        }
    }
    printf("\n");
}

static void dump_framebuffers(struct device *dev)
{
    drmModeFB *fb;
    int i;

    printf("Frame buffers:\n");
    printf("id\tsize\tpitch\n");
    for (i = 0; i < dev->resources->res->count_fbs; i++) {
        fb = dev->resources->fbs[i].fb;
        if (!fb)
            continue;

        printf("%u\t(%ux%u)\t%u\n",
               fb->fb_id,
               fb->width, fb->height,
               fb->pitch);
    }
    printf("\n");
}

static void dump_planes(struct device *dev)
{
    unsigned int i, j;

    printf("Planes:\n");
    printf("id\tcrtc\tfb\tCRTC x,y\tx,y\tgamma size\tpossible crtcs\n");

    if (!dev->resources->plane_res)
        return;

    for (i = 0; i < dev->resources->plane_res->count_planes; i++) {
        struct plane *plane = &dev->resources->planes[i];
        drmModePlane *ovr = plane->plane;
        if (!ovr)
            continue;

        printf("%d\t%d\t%d\t%d,%d\t\t%d,%d\t%-8d\t0x%08x\n",
               ovr->plane_id, ovr->crtc_id, ovr->fb_id,
               ovr->crtc_x, ovr->crtc_y, ovr->x, ovr->y,
               ovr->gamma_size, ovr->possible_crtcs);

        if (!ovr->count_formats)
            continue;

        printf("  formats:");
        for (j = 0; j < ovr->count_formats; j++)
            dump_fourcc(ovr->formats[j]);
        printf("\n");

        if (plane->props) {
            printf("  props:\n");
            for (j = 0; j < plane->props->count_props; j++)
                dump_prop(dev, plane->props_info[j],
                      plane->props->props[j],
                      plane->props->prop_values[j]);
        } else {
            printf("  no properties found\n");
        }
    }
    printf("\n");

    return;
}

static void free_resources(struct resources *res)
{
    int i;

    if (!res)
        return;

#define free_resource(_res, __res, type, Type)					\
    do {									\
        if (!(_res)->type##s)						\
            break;							\
        for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) {	\
            if (!(_res)->type##s[i].type)				\
                break;						\
            drmModeFree##Type((_res)->type##s[i].type);		\
        }								\
        free((_res)->type##s);						\
    } while (0)

#define free_properties(_res, __res, type)					\
    do {									\
        for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) {	\
            drmModeFreeObjectProperties(res->type##s[i].props);	\
            free(res->type##s[i].props_info);			\
        }								\
    } while (0)

    if (res->res) {
        free_properties(res, res, crtc);

        free_resource(res, res, crtc, Crtc);
        free_resource(res, res, encoder, Encoder);

        for (i = 0; i < res->res->count_connectors; i++)
            free(res->connectors[i].name);

        free_resource(res, res, connector, Connector);
        free_resource(res, res, fb, FB);

        drmModeFreeResources(res->res);
    }

    if (res->plane_res) {
        free_properties(res, plane_res, plane);

        free_resource(res, plane_res, plane, Plane);

        drmModeFreePlaneResources(res->plane_res);
    }

    free(res);
}

static struct resources *get_resources(struct device *dev)
{
    struct resources *res;
    int i;

    res = calloc(1, sizeof(*res));
    if (res == 0)
        return NULL;

    drmSetClientCap(dev->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);

    res->res = drmModeGetResources(dev->fd);
    if (!res->res) {
        fprintf(stderr, "drmModeGetResources failed: %s\n",
            strerror(errno));
        goto error;
    }

    res->crtcs = calloc(res->res->count_crtcs, sizeof(*res->crtcs));
    res->encoders = calloc(res->res->count_encoders, sizeof(*res->encoders));
    res->connectors = calloc(res->res->count_connectors, sizeof(*res->connectors));
    res->fbs = calloc(res->res->count_fbs, sizeof(*res->fbs));

    if (!res->crtcs || !res->encoders || !res->connectors || !res->fbs)
        goto error;

#define get_resource(_res, __res, type, Type)					\
    do {									\
        for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) {	\
            (_res)->type##s[i].type =				\
                drmModeGet##Type(dev->fd, (_res)->__res->type##s[i]); \
            if (!(_res)->type##s[i].type)				\
                fprintf(stderr, "could not get %s %i: %s\n",	\
                    #type, (_res)->__res->type##s[i],	\
                    strerror(errno));			\
        }								\
    } while (0)

    get_resource(res, res, crtc, Crtc);
    get_resource(res, res, encoder, Encoder);
    get_resource(res, res, connector, Connector);
    get_resource(res, res, fb, FB);

    /* Set the name of all connectors based on the type name and the per-type ID. */
    for (i = 0; i < res->res->count_connectors; i++) {
        struct connector *connector = &res->connectors[i];
        drmModeConnector *conn = connector->connector;
        int num;

        num = asprintf(&connector->name, "%s-%u",
             "gwj-unkown",
             conn->connector_type_id);
        if (num < 0)
            goto error;
    }

#define get_properties(_res, __res, type, Type)					\
    do {									\
        for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) {	\
            struct type *obj = &res->type##s[i];			\
            unsigned int j;						\
            obj->props =						\
                drmModeObjectGetProperties(dev->fd, obj->type->type##_id, \
                               DRM_MODE_OBJECT_##Type); \
            if (!obj->props) {					\
                fprintf(stderr,					\
                    "could not get %s %i properties: %s\n", \
                    #type, obj->type->type##_id,		\
                    strerror(errno));			\
                continue;					\
            }							\
            obj->props_info = calloc(obj->props->count_props,	\
                         sizeof(*obj->props_info));	\
            if (!obj->props_info)					\
                continue;					\
            for (j = 0; j < obj->props->count_props; ++j)		\
                obj->props_info[j] =				\
                    drmModeGetProperty(dev->fd, obj->props->props[j]); \
        }								\
    } while (0)

    get_properties(res, res, crtc, CRTC);
    get_properties(res, res, connector, CONNECTOR);

    for (i = 0; i < res->res->count_crtcs; ++i)
        res->crtcs[i].mode = &res->crtcs[i].crtc->mode;

    res->plane_res = drmModeGetPlaneResources(dev->fd);
    if (!res->plane_res) {
        fprintf(stderr, "drmModeGetPlaneResources failed: %s\n",
            strerror(errno));
        return res;
    }

    res->planes = calloc(res->plane_res->count_planes, sizeof(*res->planes));
    if (!res->planes)
        goto error;

    get_resource(res, plane_res, plane, Plane);
    get_properties(res, plane_res, plane, PLANE);

    return res;

error:
    free_resources(res);
    return NULL;
}

int drm_set_prop(int fd,unsigned int object_id, const char *prop_name, int prop_val)
{

    drmModeObjectPropertiesPtr props;
    int ret = -1;

    props = drmModeObjectGetProperties(fd, object_id, DRM_MODE_OBJECT_PLANE);
    if (!props) {
        return ret;
    }

    for (size_t i = 0; i < props->count_props; i++) {
        drmModePropertyPtr prop = drmModeGetProperty(fd, props->props[i]);

        if (!strcmp(prop->name, prop_name)) {
            ret = drmModeObjectSetProperty(fd, object_id,
                                           DRM_MODE_OBJECT_PLANE,
                                           prop->prop_id,
                                           prop_val);
            drmModeFreeProperty(prop);
            break;
        }
        drmModeFreeProperty(prop);
    }
    drmModeFreeObjectProperties(props);

    return ret;
}

int bo_create_dumb(int fd, struct drm_buffer_object *bo,unsigned int width, unsigned int height, unsigned int bpp)
{
    struct drm_mode_create_dumb arg;
//    struct drm_buffer_object *bo;
    int ret;

//    bo = calloc(1, sizeof(*bo));
//    if (bo == NULL) {
//        fprintf(stderr, "failed to allocate buffer object\n");
//        return NULL;
//    }
    memset(&arg, 0, sizeof(arg));
    arg.bpp = bpp;
    arg.width = width;
    arg.height = height;

    pr_db("gwj---bo->bpp : %d bo->width : %d  bo->height : %d\r\n",arg.bpp,arg.width,arg.height);

    ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &arg);
    if (ret) {
        fprintf(stderr, "failed to create dumb buffer: %s\n",
            strerror(errno));
        free(bo);
        return 0;
    }

    bo->fd = fd;
    bo->handle = arg.handle;
    bo->size = arg.size;
    bo->pitch = arg.pitch;
    bo->bpp=arg.bpp;
    pr_db("gwj---bo->size : %d bo->pitch : %d\r\n",arg.size,arg.pitch);


    return 0;
}


void bo_create(int fd,struct drm_buffer_object *bo, unsigned int format,
      unsigned int width, unsigned int height,
      unsigned int handles[4], unsigned int pitches[4],
      unsigned int offsets[4])
{
    unsigned int virtual_height;
//    struct drm_buffer_object *bo;
    unsigned int bpp;
    void *virtual;
    int ret;

    switch (format) {
    case DRM_FORMAT_C8:
    case DRM_FORMAT_NV12:
    case DRM_FORMAT_NV21:
    case DRM_FORMAT_NV16:
    case DRM_FORMAT_NV61:
    case DRM_FORMAT_YUV420:
    case DRM_FORMAT_YVU420:
        bpp = 8;
        break;

    case DRM_FORMAT_ARGB4444:
    case DRM_FORMAT_XRGB4444:
    case DRM_FORMAT_ABGR4444:
    case DRM_FORMAT_XBGR4444:
    case DRM_FORMAT_RGBA4444:
    case DRM_FORMAT_RGBX4444:
    case DRM_FORMAT_BGRA4444:
    case DRM_FORMAT_BGRX4444:
    case DRM_FORMAT_ARGB1555:
    case DRM_FORMAT_XRGB1555:
    case DRM_FORMAT_ABGR1555:
    case DRM_FORMAT_XBGR1555:
    case DRM_FORMAT_RGBA5551:
    case DRM_FORMAT_RGBX5551:
    case DRM_FORMAT_BGRA5551:
    case DRM_FORMAT_BGRX5551:
    case DRM_FORMAT_RGB565:
    case DRM_FORMAT_BGR565:
    case DRM_FORMAT_UYVY:
    case DRM_FORMAT_VYUY:
    case DRM_FORMAT_YUYV:
    case DRM_FORMAT_YVYU:
        bpp = 16;
        break;

    case DRM_FORMAT_BGR888:
    case DRM_FORMAT_RGB888:
        bpp = 24;
        break;

    case DRM_FORMAT_ARGB8888:
    case DRM_FORMAT_XRGB8888:
    case DRM_FORMAT_ABGR8888:
    case DRM_FORMAT_XBGR8888:
    case DRM_FORMAT_RGBA8888:
    case DRM_FORMAT_RGBX8888:
    case DRM_FORMAT_BGRA8888:
    case DRM_FORMAT_BGRX8888:
    case DRM_FORMAT_ARGB2101010:
    case DRM_FORMAT_XRGB2101010:
    case DRM_FORMAT_ABGR2101010:
    case DRM_FORMAT_XBGR2101010:
    case DRM_FORMAT_RGBA1010102:
    case DRM_FORMAT_RGBX1010102:
    case DRM_FORMAT_BGRA1010102:
    case DRM_FORMAT_BGRX1010102:
        bpp = 32;
        break;
//gwj compatibility setting
//    case DRM_FORMAT_XRGB16161616F:
//    case DRM_FORMAT_XBGR16161616F:
//    case DRM_FORMAT_ARGB16161616F:
//    case DRM_FORMAT_ABGR16161616F:
//        bpp = 64;
//        break;

    default:
        fprintf(stderr, "unsupported format 0x%08x\n",  format);
//        return NULL;
    }

    switch (format) {
    case DRM_FORMAT_NV12:
    case DRM_FORMAT_NV21:
    case DRM_FORMAT_YUV420:
    case DRM_FORMAT_YVU420:
        virtual_height = height * 3 / 2;
        break;

    case DRM_FORMAT_NV16:
    case DRM_FORMAT_NV61:
        virtual_height = height * 2;
        break;

    default:
        virtual_height = height;
        break;
    }

    bo_create_dumb(fd,bo, width, virtual_height, bpp);

    /* just testing a limited # of formats to test single
     * and multi-planar path.. would be nice to add more..
     */
    switch (format) {
    case DRM_FORMAT_UYVY:
    case DRM_FORMAT_VYUY:
    case DRM_FORMAT_YUYV:
    case DRM_FORMAT_YVYU:
        offsets[0] = 0;
        handles[0] = bo->handle;
        pitches[0] = bo->pitch;

        break;

    case DRM_FORMAT_NV12:
    case DRM_FORMAT_NV21:
    case DRM_FORMAT_NV16:
    case DRM_FORMAT_NV61:
        offsets[0] = 0;
        handles[0] = bo->handle;
        pitches[0] = bo->pitch;
        pitches[1] = pitches[0];
        offsets[1] = pitches[0] * height;
        handles[1] = bo->handle;

        break;

    case DRM_FORMAT_YUV420:
    case DRM_FORMAT_YVU420:
        offsets[0] = 0;
        handles[0] = bo->handle;
        pitches[0] = bo->pitch;
        pitches[1] = pitches[0] / 2;
        offsets[1] = pitches[0] * height;
        handles[1] = bo->handle;
        pitches[2] = pitches[1];
        offsets[2] = offsets[1] + pitches[1] * height / 2;
        handles[2] = bo->handle;

        break;

    case DRM_FORMAT_C8:
    case DRM_FORMAT_ARGB4444:
    case DRM_FORMAT_XRGB4444:
    case DRM_FORMAT_ABGR4444:
    case DRM_FORMAT_XBGR4444:
    case DRM_FORMAT_RGBA4444:
    case DRM_FORMAT_RGBX4444:
    case DRM_FORMAT_BGRA4444:
    case DRM_FORMAT_BGRX4444:
    case DRM_FORMAT_ARGB1555:
    case DRM_FORMAT_XRGB1555:
    case DRM_FORMAT_ABGR1555:
    case DRM_FORMAT_XBGR1555:
    case DRM_FORMAT_RGBA5551:
    case DRM_FORMAT_RGBX5551:
    case DRM_FORMAT_BGRA5551:
    case DRM_FORMAT_BGRX5551:
    case DRM_FORMAT_RGB565:
    case DRM_FORMAT_BGR565:
    case DRM_FORMAT_BGR888:
    case DRM_FORMAT_RGB888:
    case DRM_FORMAT_ARGB8888:
    case DRM_FORMAT_XRGB8888:
    case DRM_FORMAT_ABGR8888:
    case DRM_FORMAT_XBGR8888:
    case DRM_FORMAT_RGBA8888:
    case DRM_FORMAT_RGBX8888:
    case DRM_FORMAT_BGRA8888:
    case DRM_FORMAT_BGRX8888:
    case DRM_FORMAT_ARGB2101010:
    case DRM_FORMAT_XRGB2101010:
    case DRM_FORMAT_ABGR2101010:
    case DRM_FORMAT_XBGR2101010:
    case DRM_FORMAT_RGBA1010102:
    case DRM_FORMAT_RGBX1010102:
    case DRM_FORMAT_BGRA1010102:
    case DRM_FORMAT_BGRX1010102:
//gwj compatibility setting
//    case DRM_FORMAT_XRGB16161616F:
//    case DRM_FORMAT_XBGR16161616F:
//    case DRM_FORMAT_ARGB16161616F:
//    case DRM_FORMAT_ABGR16161616F:
        offsets[0] = 0;
        handles[0] = bo->handle;
        pitches[0] = bo->pitch;

        break;
    }

//    return bo;
}

static int modeset_create_fb(int fd, uint32_t width, uint32_t height , uint32_t color)
{
    int fb_id;
    struct drm_mode_create_dumb create = {};
    struct drm_mode_map_dumb map = {};
    uint32_t i;
    char* vaddr;

    create.width = width;
    create.height = height;
    create.bpp = 24;
    drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create);

//    bo->pitch = create.pitch;
//    printf("create.pitch:%d\n",create.pitch);
//    bo->size = create.size;
//    bo->handle = create.handle;
    drmModeAddFB(fd, width, height, 24, 24, create.pitch,
               create.handle, &fb_id);

    map.handle = create.handle;
    drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map);
//    bo->vaddr = mmap(0,create.size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,map.offset);
    vaddr = mmap(0, create.size, PROT_READ | PROT_WRITE,MAP_SHARED, fd, map.offset);
//    for (i = 0; i <bo->size; i++)
//        bo->vaddr[i] = color;
    memset(vaddr,color,create.size);

    return fb_id;
}

struct drm_buffer_object *
modeset_create_fb2(int fd,struct drm_plane *p)
{
    struct drm_buffer_object *bo;
    uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
    struct drm_mode_map_dumb map = {};

    bo=calloc(1,sizeof(*p->bo));
        if (bo == NULL) {
            fprintf(stderr, "failed to allocate buffer object\n");
            return NULL;
        }
    bo_create(fd,bo,p->fourcc,p->w,p->h,handles,pitches,offsets);

    /* just use single plane format for now.. */
    if (drmModeAddFB2(fd, p->w, p->h, p->fourcc,
            handles, pitches, offsets, &p->fb_id, 0)) {
        fprintf(stderr, "failed to add fb: %s\n", strerror(errno));
        return -1;
    }

    map.handle = bo->handle;
    drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map);

    bo->vaddr = mmap(0, bo->size, PROT_READ | PROT_WRITE,
            MAP_SHARED, fd, map.offset);

    memset(bo->vaddr, 0xff, bo->size);

//    munmap(bo->vaddr, bo->size);

    return 0;
}

//gwj:destroy one buf;
void bo_destroy(struct drm_buffer_object *bo)
{
    struct drm_mode_destroy_dumb arg;
    int ret;

    memset(&arg, 0, sizeof(arg));
    arg.handle = bo->handle;

    ret = drmIoctl(bo->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &arg);
    if (ret)
        fprintf(stderr, "failed to destroy dumb buffer: %s\n",
            strerror(errno));
    munmap(bo->vaddr, bo->size);

    free(bo);
}
//gwj:destroy more buf;
void drm_bufs_destroy(struct drm_buffer_object *bufs,int buf_num)
{
    struct drm_buffer_object *bo;
    struct drm_mode_destroy_dumb arg;
    int ret;

    for(int i=0;i<buf_num;i++){
        bo=&bufs[i];
        memset(&arg, 0, sizeof(arg));
        arg.handle = bo->handle;
        ret = drmIoctl(bo->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &arg);
        if (ret)
            fprintf(stderr, "failed to destroy dumb buffer: %s\n",
                strerror(errno));
        munmap(bo->vaddr, bo->size);
    }
    free(bufs);
}


int init_drm_bufs(int fd,struct drm_buffers *drm_bufs,int32_t width,int32_t height,int buf_num,unsigned int fourcc){
    drm_bufs->buf_num=buf_num;
    drm_bufs->height=height;
    drm_bufs->width=width;
    drm_bufs->fourcc=fourcc;
    drm_bufs->bo=calloc(buf_num,sizeof(*drm_bufs->bo));
    if (drm_bufs->bo == NULL) {
        fprintf(stderr, "failed to allocate buffer object\n");
        return NULL;
    }
    printf("sieof :%d  %d\r\n",sizeof(*drm_bufs->bo),sizeof(struct drm_buffers));

    uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
    struct drm_mode_map_dumb map = {};

    for(int i=0;i<buf_num;i++){
        struct drm_buffer_object *bo=&drm_bufs->bo[i];
        bo_create(fd,bo,fourcc,width,height,handles,pitches,offsets);

        /* just use single plane format for now.. */
        if (drmModeAddFB2(fd, width, height, fourcc,
                handles, pitches, offsets, &(bo->fb_id), 0)) {
            fprintf(stderr, "failed to add fb: %s\n", strerror(errno));
            return -1;
        }

        map.handle = bo->handle;
        drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map);

        bo->vaddr = mmap(0, bo->size, PROT_READ | PROT_WRITE,
                MAP_SHARED, fd, map.offset);

        memset(bo->vaddr, 0xff, bo->size);
    }

    return 0;
}

int plane_bind_buf(int fd, struct drm_plane *p,struct drm_buffer_object plane_bo)
{
    uint32_t plane_id;
    uint32_t crtc_id;
    int crtc_x, crtc_y, crtc_w, crtc_h;

    plane_id = p->plane_id;
    crtc_id=p->crtc_id;
    crtc_w = p->w * p->scale;
    crtc_h = p->h * p->scale;
    crtc_x = p->x;
    crtc_y = p->y;
    /* note src coords (last 4 args) are in Q16 format */
    if (drmModeSetPlane(fd, plane_id, crtc_id, plane_bo.fb_id,
                0, crtc_x, crtc_y, crtc_w, crtc_h,
                0, 0, p->w << 16, p->h << 16)) {
        fprintf(stderr, "failed to enable plane,maby color buffer format not correct:%s\n",
            strerror(errno));
        return -1;
    }
    return 0;
}
//打印drm分层信息。包括层id以及对应层支持的显示格式。
// crtc id : 38 
// Planes:
// id	crtc	fb	CRTC x,y	x,y	gamma size	possible crtcs
// 33	0	0	0,0		0,0	0       	0x00000001
//   formats: NV12
// 34	0	0	0,0		0,0	0       	0x00000001
//   formats: NV12
// 35	0	0	0,0		0,0	0       	0x00000001
//   formats: NV12
// 36	0	0	0,0		0,0	0       	0x00000001
//   formats: BG24
// 37	38	48	0,0		0,0	0       	0x00000001
//   formats: RG24
//drm_print_v2
int drm_card_print_info(struct drm_card drm_info){
    struct device dev;
    int encoders = 1, connectors = 1, crtcs = 1, planes = 1, framebuffers = 1;
    memset(&dev,0,sizeof (dev));

    dev.fd=drm_info.fd;
    dev.resources = get_resources(&dev);
    if (!dev.resources) {
        pr_db("gwj drm_print_test erro\r\n")
        return -1;
    }
#define dump_resource(dev, res) if (res) dump_##res(dev)

    dump_resource(&dev, encoders);
    dump_resource(&dev, connectors);
    dump_resource(&dev, crtcs);
    dump_resource(&dev, planes);
    dump_resource(&dev, framebuffers);
}
//drm_print_v1
int drm_print_v1(struct drm_card drm_info){
    drmModeConnector *conn;
    drmModeRes *res;
    drmModePlaneRes *plane_res;
    int crtc_id,conn_id,fd;

    fd=drm_info.fd;

    res = drmModeGetResources(fd);
    if(!res)
    {
        printf("drmModeGetResources fail");
        drmModeFreeResources(res);
        return -1;
    }
    crtc_id = res->crtcs[0];
    conn_id = res->connectors[0];
    printf("crtc id : %d \r\n",crtc_id);
    drmSetClientCap(fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
    plane_res = drmModeGetPlaneResources(fd);
    if(!plane_res)
    {
        printf("drmModeGetPlaneResources fail\r\n");
        drmModeFreeResources(res);
        drmModeFreePlaneResources(plane_res);
        return -2;
    }

    conn = drmModeGetConnector(fd, conn_id);
    if(!conn)
    {
        pr_db("drmModeGetConnector fail\r\n");
        drmModeFreeConnector(conn);
        return -1;
    }
    if(conn->count_modes <= 0)
    {
        pr_db("none monitor mode found\r\n");
         drmModeFreeConnector(conn);
         drmModeFreeResources(res);
         drmModeFreePlaneResources(plane_res);
        return -1;
    }
    for(int i=0;i<conn->count_modes;i++){
        pr_db("list screen mode[%d]:%dx%d@%d\r\n",i,
               conn->modes[i].hdisplay,
               conn->modes[i].vdisplay,
               conn->modes[i].vrefresh);
    }

    printf("Planes:\n");
        printf("id\tcrtc\tfb\tCRTC x,y\tx,y\tgamma size\tpossible crtcs\r\n");
    for(int i=0;i<plane_res->count_planes;i++){
//        struct plane *plane = plane_res->planes[i];
        drmModePlane *ovr = drmModeGetPlane(fd,plane_res->planes[i]);
        if (!ovr)
            continue;
        printf("%d\t%d\t%d\t%d,%d\t\t%d,%d\t%-8d\t0x%08x\r\n",
               ovr->plane_id, ovr->crtc_id, ovr->fb_id,
               ovr->crtc_x, ovr->crtc_y, ovr->x, ovr->y,
               ovr->gamma_size, ovr->possible_crtcs);

        if (!ovr->count_formats)
            continue;

        printf("  formats:");
        for (int j = 0; j < ovr->count_formats; j++)
            dump_fourcc(ovr->formats[j]);
        printf("\r\n");
    }

    drmModeFreeConnector(conn);
    drmModeFreeResources(res);
    drmModeFreePlaneResources(plane_res);
    return 0;
}


int drm_card_init(struct drm_card *card_info,char *name){
    drmModeRes *res;

    card_info->fd = open(name, O_RDWR | O_CLOEXEC);
    if(card_info->fd < 0)
    {
        fprintf(stderr,"open /dev/dri/%s fail",name);
        return -1;
    }
    res = drmModeGetResources(card_info->fd);
    if(!res)
    {
        pr_db("drmModeGetResources fail\r\n");
        drmModeFreeResources(res);
        return -1;
    }
    card_info->crtc_id = res->crtcs[0];
    card_info->conn_id = res->connectors[0];
    pr_db("drm_card_init crtc id is :%d\r\n",card_info->crtc_id);
    drmModeFreeResources(res);
    return -1;
}
//设置drm分层的透明度属性。范围0-255.
int drm_alpha_init(struct drm_card drm_info){
    drm_set_prop( drm_info.fd, 33, "alpha", 180);//yuv
    drm_set_prop( drm_info.fd, 34, "alpha", 180);//yuv
    drm_set_prop( drm_info.fd, 35, "alpha", 160);//yuv
    drm_set_prop( drm_info.fd, 36, "alpha", 160);//yuv
//    drm_set_prop( drm_info.fd, 37, "alpha", 160);//yuv
//    drm_set_prop( drm_info.fd, 38, "alpha", 180);//RGB
    return 0;
};

int print_crtc_mode(struct drm_card drm_info)
{
    int fd;
    drmModeConnector *conn;
    uint32_t conn_id;
    uint32_t crtc_id;

    int screen_index = -1;

    fd = drm_info.fd;
    crtc_id = drm_info.crtc_id;
    conn_id = drm_info.conn_id;

    conn = drmModeGetConnector(fd, conn_id);
    if(!conn)
    {
        pr_db("drmModeGetConnector fail");
        drmModeFreeConnector(conn);
        return -1;
    }
    if(conn->count_modes <= 0)
    {
        pr_db("none monitor mode found");
         drmModeFreeConnector(conn);
        return -1;
    }
    for(int i=0;i<conn->count_modes;i++){
        pr_db("list screen mode[%d]:%dx%d@%d",i,
               conn->modes[i].hdisplay,
               conn->modes[i].vdisplay,
               conn->modes[i].vrefresh);
    }

    drmModeFreeConnector(conn);

    return -1;
}
int set_crtc_mode(struct drm_card drm_info,int mode_index)
{
    int fd,ret,fb_id;
    drmModeConnector *conn;
    uint32_t conn_id;
    uint32_t crtc_id;

    int screen_index = -1;

    fd = drm_info.fd;
    crtc_id = drm_info.crtc_id;
    conn_id = drm_info.conn_id;

    conn = drmModeGetConnector(fd, conn_id);
    if(!conn)
    {
        pr_db("drmModeGetConnector fail");
        drmModeFreeConnector(conn);
        return -1;
    }
    if(conn->count_modes <= 0)
    {
        pr_db("none monitor mode found");
         drmModeFreeConnector(conn);
        return -1;
    }
    screen_index=0;
    if(mode_index<=screen_index)
    pr_db("set screen:%dx%d@%d",
           conn->modes[mode_index].hdisplay,
           conn->modes[mode_index].vdisplay,
           conn->modes[mode_index].vrefresh);

    fb_id=modeset_create_fb(fd,conn->modes[mode_index].vdisplay,conn->modes[mode_index].hdisplay ,0xff);

    ret=drmModeSetCrtc(fd, crtc_id, fb_id,
                   0, 0,
                   &conn_id, 1,
                   &conn->modes[mode_index]);
    if (ret) {
        fprintf(stderr, "failed to set mode: %s\n", strerror(errno));
    }
//    drmModeDirtyFB(fd, -1, NULL, 0);

    drmModeFreeConnector(conn);

    return -1;
}

int set_crtc_mode_v2(struct drm_card drm_info,int mode_index,unsigned int fourcc)
{
    uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
    uint32_t crtc_id;
    struct drm_buffer_object *plane_bo;
    uint32_t plane_flags = 0;
    int crtc_x, crtc_y, crtc_w, crtc_h;
    struct drm_mode_create_dumb create = {};
    struct drm_mode_map_dumb map = {};
    int fd;
    struct drm_plane p;
    int ret,fb_id;
    drmModeConnector *conn;
    uint32_t conn_id;

    fd = drm_info.fd;
    crtc_id = drm_info.crtc_id;
    conn_id = drm_info.conn_id;

//    plane->fd=fd;

    conn = drmModeGetConnector(fd, conn_id);
    if(!conn)
    {
        pr_db("drmModeGetConnector fail");
        drmModeFreeConnector(conn);
        return -1;
    }
    if(conn->count_modes <= 0)
    {
        pr_db("none monitor mode found");
         drmModeFreeConnector(conn);
        return -1;
    }
    if(mode_index>(conn->count_modes))
        mode_index=0;

    pr_db("set screen:%dx%d@%d\r\n",
           conn->modes[mode_index].hdisplay,
           conn->modes[mode_index].vdisplay,
           conn->modes[mode_index].vrefresh);

    p.crtc_id = drm_info.crtc_id;

    p.w = conn->modes[mode_index].hdisplay;
    p.h = conn->modes[mode_index].vdisplay;
    p.scale = 1.0;
    p.fourcc = fourcc;
    p.buf_num=2;
    p.fd=drm_info.fd;

    crtc_id=p.crtc_id;
    p.bo=NULL;
    p.bo=calloc(p.buf_num,sizeof(*p.bo));
//    printf("gjw-size::%d \r\n",sizeof(*p->bo));
    if (p.bo == NULL) {
        fprintf(stderr, "failed to allocate buffer object\n");
        return NULL;
    }

    for(int i=0;i<p.buf_num;i++){
        plane_bo=&(p.bo[i]);
        plane_bo->fb_id=0;
        plane_bo->vaddr=NULL;
        plane_bo->size=0;
        bo_create(fd,plane_bo, p.fourcc, p.w, p.h, handles,
                     pitches, offsets);
        plane_bo->fd=fd;
        map.handle = plane_bo->handle;
        if (drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map)){
            sprintf(stderr,"DRM_IOCTL_MODE_MAP_DUMB erro");
            free(p.bo);
            p.bo=NULL;
            return -1;
        }
        plane_bo->vaddr = mmap(0, plane_bo->size, PROT_READ | PROT_WRITE,
                MAP_SHARED, fd, map.offset);

        memset(plane_bo->vaddr, 0x80, plane_bo->size);
        /* just use single plane format for now.. */
        if (drmModeAddFB2(fd, p.w, p.h, p.fourcc,
                handles, pitches, offsets, &plane_bo->fb_id, plane_flags)) {
            fprintf(stderr, "failed to add fb: %s\n", strerror(errno));
            free(p.bo);
            p.bo=NULL;
            return -1;
        }
        printf("gwj---fb_id:%d addr:0x%x size :%d\r\n",plane_bo->fb_id,plane_bo->vaddr,plane_bo->size);
    }
    p.current_buf_index=0;
    ret=drmModeSetCrtc(fd, crtc_id, p.bo[p.current_buf_index].fb_id,
                   0, 0,
                   &conn_id, 1,
                   &conn->modes[mode_index]);
    if (ret) {
        fprintf(stderr, "failed to set mode: %s\n", strerror(errno));
    }
//    drmModeDirtyFB(fd, -1, NULL, 0);

    drmModeFreeConnector(conn);

    return 0;
}
//初始化plane[0]，绑定drm显示plane id：33,crtc id：38，plane层大小为1280x720，plane层位置为0，0.plane层格式为DRM_FORMAT_NV12
//调用示例 init_plane(&plane[0],33,38,1280,720,0,0,DRM_FORMAT_NV12);
int init_plane(struct drm_plane *plane,struct drm_card drm_info,uint32_t plane_id, uint32_t width, uint32_t height,int32_t x,int32_t y,unsigned int fourcc)
{
//    plane->fd=fd;
    if(plane->bo!=NULL){
        fprintf(stderr,"plane already init\r\n");
        return -1;
    }

    plane->plane_id = plane_id;

    plane->crtc_id = drm_info.crtc_id;

    plane->w = width;
    plane->h = height;
    plane->x=x;
    plane->y=y;
    plane->scale = 1.0;
    plane->fourcc = fourcc;
    plane->buf_num=2;


    plane->fd=drm_info.fd;
    set_plane(plane);
    return 0;
}
int set_plane( struct drm_plane *p)
{
    uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
    uint32_t plane_id;
    uint32_t crtc_id;
    struct drm_buffer_object *plane_bo;
    uint32_t plane_flags = 0;
    int crtc_x, crtc_y, crtc_w, crtc_h;
    struct drm_mode_create_dumb create = {};
    struct drm_mode_map_dumb map = {};
    int fd=p->fd;


    plane_id = p->plane_id;
    crtc_id=p->crtc_id;
    p->bo=NULL;
    p->bo=calloc(p->buf_num,sizeof(*p->bo));
//    printf("gjw-size::%d \r\n",sizeof(*p->bo));
    if (p->bo == NULL) {
        fprintf(stderr, "failed to allocate buffer object\n");
        return NULL;
    }

    for(int i=0;i<p->buf_num;i++){
        plane_bo=&(p->bo[i]);
        plane_bo->fb_id=0;
        plane_bo->vaddr=NULL;
        plane_bo->size=0;
        bo_create(fd,plane_bo, p->fourcc, p->w, p->h, handles,
                     pitches, offsets);
        plane_bo->fd=fd;
        map.handle = plane_bo->handle;
        if (drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map)){
            sprintf(stderr,"DRM_IOCTL_MODE_MAP_DUMB erro");
            free(p->bo);
            p->bo=NULL;
            return -1;
        }
        plane_bo->vaddr = mmap(0, plane_bo->size, PROT_READ | PROT_WRITE,
                MAP_SHARED, fd, map.offset);

        memset(plane_bo->vaddr, 0x80, plane_bo->size);
        /* just use single plane format for now.. */
        if (drmModeAddFB2(fd, p->w, p->h, p->fourcc,
                handles, pitches, offsets, &plane_bo->fb_id, plane_flags)) {
            fprintf(stderr, "failed to add fb: %s\n", strerror(errno));
            free(p->bo);
            p->bo=NULL;
            return -1;
        }
        printf("gwj---fb_id:%d addr:0x%x size :%d\r\n",plane_bo->fb_id,plane_bo->vaddr,plane_bo->size);
    }
    p->current_buf_index=0;
    plane_switch_buffer(p,0);
    return 0;
}
//更新plane[0]的显存空间。


int plane_fb_cpy(struct drm_plane *p,void * addr,unsigned int size){
    unsigned int byte_per_line=p->w*p->bo[0].bpp/8;
    unsigned int pitch=p->bo[0].pitch;
    int index=p->current_buf_index;
    if(p->bo!=NULL){
        if(size<=p->bo[index].size){
            if(byte_per_line!=pitch){
                for(unsigned int i=0;i<p->h;i++){
                    memcpy(p->bo[0].vaddr+i*pitch,addr+i*byte_per_line,byte_per_line);
                }
            }
            else{
                memcpy(p->bo[0].vaddr,addr,size);
            }
//            printf("gwj---fb_id:%d buf index:%d addr:%ld size :%d\r\n",p->bo[0].fb_id,index,p->bo[0].vaddr,size);
        }
        else{
            fprintf(stderr,"buffer size  too long\r\n");
        }
    }
    else{
        fprintf(stderr,"plane not init\r\n");
    }
}
int plane_double_fb_cpy(struct drm_plane *p,void * addr,unsigned int size){
    unsigned int byte_per_line=p->w*p->bo[0].bpp/8;
    unsigned int pitch=p->bo[0].pitch;
    int next_index=(p->current_buf_index+1)%p->buf_num;
    if(p->bo!=NULL){
        if(size<=p->bo[next_index].size){
            if(byte_per_line!=pitch){
                for(unsigned int i=0;i<p->h;i++){
                    memcpy(p->bo[next_index].vaddr+i*pitch,addr+i*byte_per_line,byte_per_line);
                }
            }
            else{
                memcpy(p->bo[next_index].vaddr,addr,size);
            }
//            printf("gwj---fb_id:%d buf index:%d addr:%ld size :%d\r\n",p->bo[next_index].fb_id,next_index,p->bo[next_index].vaddr,size);
            plane_switch_buffer(p,next_index);
            p->current_buf_index=next_index;
        }
        else{
            fprintf(stderr,"buffer size  too long \r\n");
        }
    }
    else{
        fprintf(stderr,"plane not init\r\n");
    }
}

int plane_switch_buffer(struct drm_plane *p,unsigned char buf_count){
    int crtc_x, crtc_y, crtc_w, crtc_h;
    uint32_t plane_id;
    uint32_t crtc_id;
    uint32_t plane_flags = 0;
    int fd=p->fd;
    plane_id = p->plane_id;
    crtc_id=p->crtc_id;
    crtc_w = p->w * p->scale;
    crtc_h = p->h * p->scale;
    crtc_x = p->x;
    crtc_y = p->y;
    if((p->buf_num>buf_count)&&(buf_count>=0)){
        p->fb_id=p->bo[buf_count].fb_id;
    }
    else{
        return -1;
    }

    /* note src coords (last 4 args) are in Q16 format */
    if (drmModeSetPlane(fd, plane_id, crtc_id, p->fb_id,
                plane_flags, crtc_x, crtc_y, crtc_w, crtc_h,
                0, 0, p->w << 16, p->h << 16)) {
        if(errno==2){
            fprintf(stderr, "failed to enable plane,maby crtc id not correct:%d,%s\n",
                errno,strerror(errno));
        }
        else if (errno==22) {
            fprintf(stderr, "failed to enable plane,maby plane color buffer format not correct:%d,%s\n",
                errno,strerror(errno));
        }
        else{
            fprintf(stderr, "failed to enable plane:%5d,%s\n",
                errno,strerror(errno));
        }
        return -1;
    }
    return 0;
}

int plane_destroy(struct drm_plane *plane){
    struct drm_buffer_object *bo;
    struct drm_mode_destroy_dumb arg;
    int ret;
    int buf_num;
    buf_num=plane->buf_num;

    if(plane->bo==NULL){
        fprintf(stderr, "failed to destroy plane,plane not init\n");
        return -1;
    }

    for(int i=0;i<buf_num;i++){
        bo=&(plane->bo[i]);
//        p->fb_id=p->bo[buf_count].fb_id;
        if(bo->fb_id==0){
            break;
        }
        drmModeRmFB(plane->fd,bo->fb_id);
        memset(&arg, 0, sizeof(arg));
        arg.handle = bo->handle;
        ret = drmIoctl(bo->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &arg);
        if (ret)
            fprintf(stderr, "failed to destroy dumb buffer: %s\n",
                strerror(errno));
        munmap(bo->vaddr, bo->size);
        bo->vaddr=NULL;
        bo->size=NULL;
    }

    free(plane->bo);
    plane->bo=NULL;
    return 0;
}

void plane_destroy_all(struct drm_plane *plane,int count){
    for(int i=0;i<count;i++){
        if(plane[i].bo!=NULL)
            plane_destroy(&plane[i]);
    }
}

//int maindgdfgf(int argc, char **argv)
//{
//    struct drm_plane plane;
//    int fd;
////    im

//    init_plane(&plane,33,720,720,0,0,DRM_FORMAT_NV12);
//    memset(plane.bo->vaddr,0x55,plane.bo->size);

//    set_plane(&plane);
//    sleep(5);
//    memset(plane.bo->vaddr,0xff,plane.bo->size);
//    sleep(5);
//    bo_destroy(plane.bo);
//    close(fd);

//    return 0;
//}
